Skip to content

fix(extractor): prevent folding escaped object reads - #765

Open
owjs3901 wants to merge 59 commits into
mainfrom
fix/escape-aware-folding
Open

owjs3901 wants to merge 59 commits into
mainfrom
fix/escape-aware-folding

Conversation

@owjs3901

@owjs3901 owjs3901 commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Refs #694 (G: 결정론), #695 (F: 상수 및 spread). #756과 #757을 모두 포함하는 브랜치이며, 두 PR이 모두 먼저 병합되어야 합니다.

요약

객체가 알 수 없는 코드로 전달되거나 변경된 뒤의 프로퍼티 읽기를 초기값으로 잘못 폴딩하는 문제를 수정합니다. 현재 head는 bdc9f1c5074e2b90ebf3a7da0257810c6e718dbc입니다. 이전 gate review의 scalar snapshot deferred hazard 조합, indirect eval helper global dependency, factory reassignment origin 문제는 수정했고 실제 WASM으로 재검증했습니다. 부족했던 2개 경로에 실제 parsed-source 회귀 4개를 추가한 최신 Linux CI 37431379535는 모든 4개 job 및 Rust/Bun 100% 커버리지 통과입니다. 최종 독립 gate review도 APPROVE / HIGH, 남은 blocker 없음으로 통과했습니다. 런타임 스타일링은 추가하지 않으며 사용자의 PR 검토·병합을 기다립니다.

병합 기준 커밋은 7391e11aebb604c8a73804ddf82b6301044e5f9f입니다. 테스트 모듈 충돌은 양쪽을 모두 유지했고, inline_imported_constants 스냅샷은 테스트로 재생성하여 #757의 CJS_DYNAMIC과 #756의 spread lowering을 함께 확인했습니다. #756 테스트의 이전 평가 호출은 #757의 evaluate_located 반환형으로 연결했습니다.

shadowed require 테스트는 모듈 해석을 하지 않는 경우와 실제 global require 오류로 분리했습니다. 실제 오류는 helper.ts:1:25, 소스 위치가 없는 요청의 ingress fallback은 entry.tsx:2:23으로 검증합니다. 잘못된 빈 JSX styleOrder={}는 위치 있는 파싱 오류로 검증하고, 정상 fixture는 void 0을 사용합니다. bun install이 갱신한 11개 workspace 버전 메타데이터도 같은 병합 트리에 포함했습니다. #756과 #757 중 나중에 main에 병합하는 PR에도 이 통합 변경이 필요합니다.

동작

수정 전 실제 WASM 프로브:

const make = () => ({ p: 1 });
const made = make();
watch(made);
const f = () => made.p;
export const a = css({ p: f() });
const make = () => ({ p: 1 });
const made = make();
watch(made);
const f = () => made.p;
export const a = "a-b";
// .a-b{padding:4px}

watch가 made.p를 변경할 수 있는데도 초기값을 CSS로 고정하는 것이 문제입니다. 수정 후 같은 실제 WASM 프로브는 다음 오류를 냅니다.

/src/escape.tsx:6:18: `css()` cannot use `f()` at build time: its values must be literals, theme tokens or constants, or be computed from them
/src/escape.tsx:4:7: `made` is handed here to code that may change it near `watch(made)`, so the build cannot read it as a constant; use a direct value, freeze before the first escape, or move the mutation outside the build-time computation

일반 요소의 <Box p={f()} />는 원래 f()를 CSS 변수로 전달합니다. getter/coercion/callback이 없는 plain-data 인자에 한해 JSON.stringify, String, Number, Object.keys, Object.freeze와 명시된 17개 console builtin을 read-only로 취급합니다. Shadowed/변경된 builtin, 사용자 메서드 이름만 같은 경우는 제외합니다. Object.freeze는 얕으므로 자신의 scalar slot만 보호하고 nested 객체는 보호하지 않습니다.

새로 생기는 오류

객체 escape 또는 쓰기 이후 정확성을 증명할 수 없는 값을 css, styled 템플릿, globalCss, keyframes, compat/StyleX 등 요소에 런타임 값을 전달할 수 없는 API가 읽으면 위치 있는 빌드 오류가 발생합니다. Unknown call/메서드, alias/중첩 컨테이너 전달, captured write, assignment/update/delete, Object.assign/defineProperty 계열, setter가 대상입니다. 소비 위치와 원래 binding/escape·쓰기 위치 및 코드, direct scalar/copy 전달·escape 전 freeze·변경 이동 방법을 보고합니다. 요소의 일반 스타일 값은 기존 CSS 변수 경로를 사용합니다.

남는 한계

  • 분석 범위는 한 JavaScript 모듈입니다. 다른 모듈이 exported/imported 객체를 변경하지 않는다는 기존 가정은 유지합니다.
  • 클래스 이름, resolver, JSX-02 변경은 이번 수정의 범위가 아닙니다.
  • sibling scalar helper, scalar shallow-copy helper, frozen-parent scalar helper 정밀도는 bba266d6에서 수정했고 exact-positive 22개를 모두 통과합니다.
  • 요소 prop 안의 nested runtime unknown call, runtime setTheme의 잘못된 compile-only 취급, shallow-freeze 반환 alias의 nested child 전달, direct eval의 lexical mutation 경로도 재현 후 수정했습니다. 아래 추가 프로브에서 수정 전·후를 확인합니다.

검증

  • 병합 기준 트리: WASM 빌드 및 루트 패키지 빌드 통과.
  • cargo fmt --all, Rust 1.99 clippy 및 workspace 테스트 통과: extractor 2708, CSS 530, sheet 148, WASM 42.
  • exact-tree 병합 커밋 hook 통과; Bun 5504 통과 / 0 실패 / 커버리지 100%.
  • Windows 기본 포맷 tarpaulin 기준: 97.87%, 20332/20775줄. Linux CI의 넓은 rustfmt 설정에서 100%를 별도 검증합니다.
  • apps/landing/dist/client 병합 기준 비압축 CSS 61,850바이트, JS 693,559바이트, 172개 파일. 최종 수정 후 같은 조건에서 아래 수치와 비교했습니다.
  • 18개 실제 WASM 프로브의 수정 전·후 결과와 기존 테스트, 스냅샷, 독립 프로브의 모든 변경 목록을 아래에 기록했습니다.
  • 기준 트리 Linux CI 37367102468: vinext-rsc-css-e2e 통과. publish, benchmark, landing-next-e2e는 runner를 할당받지 못하여 0개 단계 실행 후 취소되었습니다. GitHub Actions의 hosted-runner 할당 장애이며 코드 실패로 처리하지 않습니다. workflow 변경이나 반복 재실행 없이, 장애 복구 후 coordinator가 취소된 job을 재실행합니다.

핵심 수정 검증

  • 커밋된 최신 전체 Rust: extractor 3149 / CSS 530 / sheet 148 / WASM 42 통과. integration 및 doctest 포함 전체 3875개, 0 실패. Rust 1.99 clippy 통과.
  • WASM 및 루트 패키지 재빌드, Bun 5504 통과 / 0 실패 / 100% 커버리지. exact-tree 커밋 hook 통과.
  • 최신 head bdc9f1c5의 Linux Rust 커버리지는 100.00%, 15374/15374줄, Bun **5512 통과 / 0 실패 / 100%**입니다. gate 수정 직후 head ba1fee2f의 15372/15374줄 (99.99%) 실패를 실제 회귀 4개로 해결했습니다. Windows hook 측정 97.74%, 21382/21877줄과 구분하며 coverage 제외·workflow 변경으로 통과시키지 않았습니다.
  • landing, next, rsbuild, vite-lib, vite 앱 모두 빌드 통과. 모든 18개 benchmark fixture 빌드 통과. 앱·fixture 소스는 수정하지 않았고 새 빌드 오류도 없었습니다.
  • landing CSS 61,850 → 61,850바이트, JS 693,559 → 693,559바이트, 각각 172개 client CSS/JS 파일 기준.
  • 독립 실제 WASM 98개: build-only 오류 41/41, 요소 CSS 변수 35/35, exact-positive 22/22. 이후 발견한 4개 추가 재현도 모두 올바른 located error로 바뀝니다. immutable local/namespace API alias 정상 폴딩도 별도 검증했습니다.
  • 핵심 수정 CI 37388610454, head 59f2dce5: landing-next-e2e, vinext-rsc-css-e2e, benchmark 통과. publish는 실제 Rust 커버리지 99.85% (14948/14970, 22줄 부족)로 실패했습니다. 스타일 기능 실패나 외부 장애로 숨기지 않습니다.
  • scalar 수정 CI 37391632758, head bba266d6: landing-next-e2e, vinext-rsc-css-e2e, benchmark 통과. publish의 당시 실제 Rust 커버리지 실패는 추가 회귀 및 typed 구조 개선으로 해결했으며 최신 CI 결과와 구분합니다.
  • 최신 CI 37431379535, head bdc9f1c5: publish / benchmark / landing-next-e2e / vinext-rsc-css-e2e 모두 SUCCESS, Codecov patch SUCCESS. Rust100%, Bun100%, preload race 회귀 6개, landing E2E 및 Codecov upload가 모두 통과했습니다. 이전 CI 37420224038, head ba1fee2f의 실제 2줄 커버리지 실패도 기록하며 fresh gate 승인을 별도로 확인합니다.
  • LSP daemon 요청은 timeout되며 LSP-clean은 주장하지 않습니다. compiler/clippy/test 및 실제 WASM 검증을 수행했습니다.
  • Fresh ONE gate reviewer는 이전 B1/B2/B3와 최신 delta 전체, 모든 증빙을 확인하고 실제 WASM 17개를 독립 재생하여 APPROVE / HIGH를 반환했습니다. 이는 기술 검증 결과이며 GitHub PR approve나 병합을 수행한 것이 아닙니다.

기존 테스트·스냅샷 출력 변경

  • mutations::tests::changes: 실제 Array identity가 증명되지 않은 .map은 callback-element escape 대신 receiver call hazard로 분류합니다.
  • mutations::tests::escapes: unknown .forEach/.map receiver hazard, 반환값·arrow capture의 holder 그래프를 기록합니다.
  • mutations::tests::reads: plain-data가 아닌 builtin 인자와 사용자 receiver 메서드는 보수적으로 hazard를 기록합니다. plain console 사례의 정상 폴딩은 별도 17개 회귀 사례로 유지합니다.
  • tests::test_changed_constants: 증거 사례가 class/padding:4px 대신 located error로 바뀌고, 기존 changed-value 오류에 origin 코드와 fix가 추가됩니다.
  • tests::test_emotion_css_prop_reports_what_it_cannot_compile: 기존 mutation 오류에 origin 코드와 fix가 추가됩니다.
  • tests::test_values_known_only_at_runtime: 기존 imported/changed-value 오류에 fix가 추가됩니다. 성공한 요소 출력은 그대로입니다.

변경된 스냅샷은 위 테스트와 대응하는 6개뿐이며, 모두 .snap.new를 검토한 후 assertion_line을 제거하여 수락했습니다. 추가 정책 수정에서 mutations::scope_tests::a_local_named_like_a_style_api_is_not_one의 unknown f(a)를 포함한 <Box>/<Devup.Box> 두 사례는 mutation-count 0 → 1로 바뀝니다. 이는 원래의 잘못된 nested-call 예외를 거절하는 것이며 lexical shadowing 검증은 유지했습니다. mutations::tests::reads의 최종 변경은 nested JSX escape를 추가하고 잘못된 standalone freeze escape를 제거합니다.

병합 기준 extractor 2708 → 현재 3149로 441개 회귀 사례가 추가되었습니다. cause-ordering, imported origin, plain builtin, getter/coercion/callback, helper grammar, immutable compiled aliases, shallow-freeze 반환/write/receiver, direct/indirect/shadowed eval 및 source-order 경계를 실제 parsed source로 검증합니다. 테스트 약화·삭제, coverage 제외 및 새로운 lint ignore는 없습니다.

Scalar 후속 수정

scalar 결과만 원래 source span에서 인라인하며 객체 전체나 closure에 새 실행 허용을 부여하지 않습니다. 모든 hazard, 원래 lexical binding 및 TDZ/source-readiness를 검사하여 mutable child와 shadowed/deferred/alias 경로는 계속 거절합니다. 정밀도 회귀 28개를 추가했습니다.

추가 재현한 factory 재할당도 차단했습니다. let make=()=>({p:1}); make=()=>({p:5}); const made=make(); css({p:made.p})는 수정 전 잘못된 padding:4px였고, 수정 후 /src/factory-write.tsx:1:108의 located error입니다. syntax factory fast path와 Boa sparse-definition 경로 모두 semantic write를 거절하며 3개 회귀를 추가했습니다.

추가 발견·수정한 출력

재현 수정 전 수정 후
<Box p={watch(made)} /> 뒤의 css({p:made.p}) runtime watch가 남아 있어도 padding:4px 소비 위치 /src/nested-call.tsx:1:111, 원인 1:87의 made/watch 코드와 fix를 포함한 오류
setTheme(made)에서 mutating toString runtime API인데도 padding:4px 소비 위치 1:128, 원인 1:107의 made/setTheme 코드와 fix를 포함한 오류
alias=Object.freeze(made);watch(alias);made.child.p shallow child까지 padding:4px로 고정 소비 위치 1:122, 원인 1:100의 made/watch(alias) 코드와 fix를 포함한 오류
eval('made.p=2');made.p padding:4px 소비 위치 1:86, 원인 1:54의 made/eval 코드와 fix를 포함한 오류

이 4개는 동일한 입력으로 public WASM을 비교했습니다. Direct eval은 실행하지 않고 lexical visibility와 source order를 반영하는 opaque barrier로 취급합니다. Indirect eval은 globals에만 영향을 주며 이후의 builtin identity proof를 무효화합니다. Object.freeze는 같은 객체를 돌려주므로 alias의 escape도 원래 객체에 전달합니다. 기존 exact/frozen-own-scalar 및 read-only helper 사례는 유지했습니다.

별도로 발견한 dynamic spacing의 bare numeric CSS 변수 단위/배율 문제는 E/output 작업으로 coordinator가 분리했고, 이 PR에서는 해당 emitter를 수정하지 않았습니다.

Gate에서 추가 확인한 3개 수정

가장 이른 진단 원인을 고르는 것과 scalar snapshot의 안전성을 증명하는 것을 분리하여, alias를 통해 도달하는 모든 eager/deferred hazard를 검사합니다. Boa helper closure의 transitive global read에도 동일한 eval barrier를 적용합니다. 재할당된 factory의 원래 semantic write를 소비 오류까지 전달하며 오류 문구에서 binding 이름을 추측하지 않습니다.

재현 수정 전 수정 후
writer 호출 뒤 copied scalar, 이후 watch 및 deferred writer 선언 padding:4px, 요소의 width:13px build-only 위치 오류; 요소는 원래 copied를 CSS 변수로 유지
indirect eval 이후 Math를 읽는 helper width:1px 소비 1:112, Math/eval 원인 1:69 오류
make factory 재할당 소비 위치만 있는 오류 소비 1:108과 원래 make 재할당 1:58, 코드·fix 포함 오류

추가 28개 Rust 회귀와 실제 public WASM 프로브로 확인했습니다. 기존 98개 독립 프로브도 22 exact / 41 build-only error / 35 dynamic으로 모두 통과합니다. 마지막 test-only 커밋은 type-only 참조가 runtime hazard origin이 되지 않는 경우 2개와 imported scalar-copy의 foreign hazard 거절/CSS 변수 경로 2개를 추가합니다. 두 production guard를 임시로 우회하면 4개 모두 실패하고 복원하면 32개 focused 및 3875개 workspace 테스트가 통과하는 것으로 실제 회귀 검출력을 확인했습니다. 최신 Linux CI100%와 최종 fresh gate APPROVE까지 확인했습니다.

기존 실제 프로브 출력 변경

18개 중 변경된 11개를 아래에 전부 나열합니다. 나머지 7개는 compiled code/CSS/error가 동일합니다.

프로브 수정 전 수정 후
evidence .a-b{padding:4px} /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
literalEscape /src/escape.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/escape.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
method .a-b{padding:4px} /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
alias .a-b{padding:4px} /src/escape.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
nested .a-b{padding:4px} /src/escape.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
capturedWrite /src/escape.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/escape.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
assignment /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
deletion /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
assign /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
defineProperty /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/escape.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
lateFreeze .a-b{padding:4px} /src/escape.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them

독립 프로브 출력 변경

98개 중 code/CSS/error가 변경된 56개를 모두 나열합니다. 동일한 입력 소스를 비교했고, 기존 오류에 origin/fix가 추가된 변경도 포함합니다.

프로브 수정 전 수정 후
primitive-exposure .a-b{width:13px} .a-a{width:13px}
nested-sibling-scalar /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them .a-a{width:13px}
shallow-copy-scalar /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them .a-a{width:13px}
shadow-distinct-allocation .a-b{width:13px} .a-a{width:13px}
freeze-initializer .a-b{width:13px} .a-a{width:13px}
freeze-alias-before /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them .a-b{width:13px}
freeze-parent-scalar .a-b{width:13px} .a-a{width:13px}
freeze-array-scalar /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them .a-b{width:13px}
readonly-String .a-b{width:13px} .a-a{width:13px}
readonly-Number .a-b{width:13px} .a-a{width:13px}
readonly-JSON-stringify .a-b{width:13px} .a-a{width:13px}
readonly-Object-keys .a-b{width:13px} .a-a{width:13px}
readonly-api-globalCss @layer b;@layer b{body{width:13px}} .a-b{width:13px} @layer b;@layer b{body{width:13px}} .a-a{width:13px}
readonly-api-keyframes @Keyframes a-a{from{width:13px}}.a-c{width:13px} @Keyframes a-a{from{width:13px}}.a-b{width:13px}
readonly-api-createGlobalStyle @layer b;@layer b{body{width:13px}} .a-b{width:13px} @layer b;@layer b{body{width:13px}} .a-a{width:13px}
alias-chain-css .a-b{width:13px} /src/independent.tsx:8:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
destructure-holder-css .a-b{width:13px} /src/independent.tsx:8:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
let-alias-css .a-b{width:13px} /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
let-reassigned-alias-css .a-b{width:13px} /src/independent.tsx:8:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
nested-holder-alias-css .a-b{width:13px} /src/independent.tsx:8:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
partial-member-css .a-b{width:13px} /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
shallow-copy-child-css /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
scope-helper-alias-css .a-b{width:13px} /src/independent.tsx:8:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
scope-direct-read-css .a-b{width:13px} /src/independent.tsx:6:18: css() cannot use made.width at build time: its values must be literals, theme tokens or constants, or be computed from them
scope-nested-element-css .a-b{width:13px} /src/independent.tsx:6:18: css() cannot use (()=>{const local=made;return local.width})() at build time: its values must be literals, theme tokens or constants, or be computed from them
custom-join-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
custom-valueOf-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
getter-named-join-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
setter-named-valueOf-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
arrow-method-capture-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
invoked-captured-writer-css /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
escaped-captured-writer-css .a-b{width:13px} /src/independent.tsx:8:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
escaped-writer-container-css /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
late-deferred-writer-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
freeze-after-escape-alias-css /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
freeze-shallow-child-css .a-b{width:13px} /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
freeze-shallow-array-child-css .a-b{width:13px} /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
freeze-conditional-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
freeze-after-write-css /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
seal-not-freeze-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
shadow-String-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
shadow-Number-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
shadow-JSON-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
shadow-Object-keys-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
shadow-Object-freeze-css /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:7:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
String-coercion-hook-css /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
Number-coercion-hook-css /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
JSON-toJSON-hook-css /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
JSON-replacer-capture-css /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:5:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
frozen-accessor-css /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
unsafe-api-globalCss @layer b;@layer b{body{width:13px}} /src/independent.tsx:6:1: globalCss() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
unsafe-api-keyframes @Keyframes a-b{from{width:13px}} /src/independent.tsx:6:18: keyframes() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
unsafe-api-emotion-css .a-b{width:13px} /src/independent.tsx:6:18: css() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
unsafe-api-createGlobalStyle @layer b;@layer b{body{width:13px}} /src/independent.tsx:6:18: globalCss() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
unsafe-api-stylex-create .a-a{width:13px} /src/independent.tsx:6:49: stylex.create() cannot use f() at build time: its values must be literals, theme tokens or constants, or be computed from them
unsafe-css-object-structure .a-a{width:13px} /src/independent.tsx:5:22: css() cannot use made at build time: its styles must be an object literal or a constant object, or be computed from constants

owjs3901 and others added 30 commits October 1, 2026 21:16
…rations

css(a, b) composing classes whose styles the build knows, bound to css() in the file or exported by another module, merges their atoms per property, selector, breakpoint and layer, conditions included, instead of joining classes whose winner the stylesheet order picked. vanilla-extract style([...]) passes each composed style as its own argument, keeping a style composed again later.

Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…asurable

Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…JSX spreads win

Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…led order and JSX element className

Refs #688

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #689

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…uate shouldForwardProp at build time

Refs #689

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…ring

Refs #689

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #691

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
… and conditional styles

Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…h Emotion

Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…ed parameters

Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #690

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…ead through namespaces

Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…akes from the visitor

Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…eclared after their use

Refs #695, #686

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…nding

Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
owjs3901 and others added 20 commits October 5, 2026 02:47
Refs #685, #694

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #685, #694

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #685, #694

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #685, #694

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #685, #694

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #685, #694

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #685, #694

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #685, #694

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
…graphs

Refs #685, #694

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #685, #694

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #685, #694

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #685, #694

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #685, #694

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Resolve both module-declaration and regenerated snapshot conflicts; adapt the #756 source-evaluation test to #757 evaluate_located. Synchronize bun.lock workspace versions.

Split shadowed require from global resolver diagnostics, preserve entry-ingress fallback, and adapt empty JSX styleOrder to located parse rejection. Both #756 and #757 must merge first.

Refs #694, #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@github-actions

github-actions Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Changepacks

@devup-ui/wasm@1.0.83 → 1.0.84 - bindings/devup-ui-wasm/package.json

Patch

  • A project module re-exporting Devup UI (export { Box, css } from '@devup-ui/react', export * from '@devup-ui/react', export { styled as s }, export * as Devup, a default export of an import, chains of barrels and the compat entry) now works: a file importing Box or css from it compiles exactly as if it imported from the package, following the barrel through the resolver (relative paths, tsconfig paths, package exports), and hasDevupUI sees such a file. Members read from a namespace or default import of the package (Devup['css'], const { css } = Devup, Devup.css as a value) compile where the build can follow them, Devup.x for a name the package compiles being read like the named import. New build errors, located at the use: what a barrel re-exports but the build cannot read (an unresolvable export * or module, a namespace of modules re-exporting the package) is an error where its name is used instead of a runtime crash, and a namespace member read by a key the build cannot know (Devup[key]), written, or destructured in a form it cannot follow (a rest, a computed key, a default value, a nested pattern, an exported declaration, or members mixed with ones that stay at runtime) is an error that names the members to read. A namespace passed on whole (Object.keys(Devup), spyOn(Devup, 'css'), export default Devup) is left as it is
  • css(a, b) composing classes whose styles the build knows (a const bound to css() in the file, or a css() result another module exports with a rule object every value of which is known) merges their styles: a later part's declaration replaces an earlier one's for the same property, selector, breakpoint and layer, also under conditions (css(base, cond && danger)) and for ||/?? parts, where the classes used to be joined and the stylesheet order picked the winner. vanilla-extract style([a, b]) passes each composed style as its own argument, so the later one wins, and a style composed again later (style([a, b, a])) is kept. Classes the build does not know (strings, props, CSS Modules) are kept as they are
  • styled(Base) extending a styled component the file binds to a const renders Base's tag directly with Base's styles composed under its own, so the extension's declarations replace Base's for the same property, selector, breakpoint and layer instead of losing to them by stylesheet order; Base's attrs apply before the extension's. attrs merge as styled-components merges them: className is joined with the caller's, style is merged and other props replace earlier ones. On an element, a className or style spread after the explicit prop now wins, as React merges props in the order they are written
  • Emotion's now compiles at build time with no runtime: the element becomes what its child function ({ css, cx, theme }) => ... renders, each css and cx call becomes the classes it composes (later styles replace earlier ones; css reads strings as CSS text and its tagged templates split around mixins; cx keeps unknown classes, reads { name: condition } objects as conditional classes and composes nested css and cx calls), and theme.a.b in their values becomes var(--a-b). Numbers in css rules are px lengths, as Emotion reads them, and top-level constants are inlined. New build errors, each at file:line:col: a without exactly one child function taking { css, cx, theme } that gives what it renders at once (attributes, other children, rest or default parameters, async or generator functions, several statements); reading the theme other than as theme.a.b in a css value; using css or cx other than by calling them; a cx object with a spread, getter or method; parts css and cx cannot compose (runtime calls, spreads, a condition choosing between styles and classes). @devup-ui/react/compat exports ClassNames with the ClassNamesContent and ClassNamesArg types, and the @emotion/react declarations include them
  • Emotion and styled-components component selectors now compile at build time: a styled component the file defines that another style selects (${Child} { ... } in CSS text, [Child] or [&:hover ${Child}] as a rule key) gets a short marker class, which only such components get, and the selector reads it as .marker; a component extending it, or an element inlining it for its css prop, keeps the marker. Selectors written without & now nest under the component as stylis nests them (ul { ... } is & ul, a selector list nests each selector, :hover applies to the component itself) instead of becoming global rules, and rule-object keys starting with ., #, [, *, >, + or ~ are read as nested selectors instead of properties
  • Emotion's css prop compiles at build time while @emotion/react is aliased: on tags and Devup UI components always, and on every element once the file imports @emotion/react or @emotion/styled or names @emotion/react in a @jsxImportSource pragma; jsx, jsxs and jsxDEV from @emotion/react/jsx-runtime (or jsx-dev-runtime) and jsx from @emotion/react compile it too, so libraries built with Emotion's JSX runtime do as well. The prop becomes the element's className, with CSS variables in its style for values only the runtime gives: arrays and conditions compose with a later part replacing what an earlier one sets, css() classes the file knows compose by their styles, strings and templates are CSS text, css`` mixins split the text around them, a function of the theme reads theme.a.b as var(--a-b), unitless numbers are px as in Emotion (constants included), and a className holding known css() classes overrides the prop as Emotion's registered classes do. A styled component the file defines renders its tag in the element's place when the prop overrides its styles and it renders a tag with no attrs or props read and the element has no spread, as or forwardedAs. Emotion's JSX runtime imports become react/jsx-runtime, the pragma names react, and jsx comes from @devup-ui/react/compat (React's createElement); @devup-ui/react/compat/css-prop types the prop on React.Attributes. New build errors, each with file:line:column and the code: a css prop part the build cannot read (a call, an element), a style object declared inside a function or with let, a binding only running the module gives or code changes, a theme function that does more than return rules or reads the theme other than as theme.a.b in a value, an interpolation CSS text cannot place or a mixin inside a nested rule, and a css prop overriding a styled component's styles where its tag cannot be rendered in place. Composing css() with a part that reads a known binding (such as a keyframes name) now reads its value
  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • Prevent stale build-time folding after module-local object escapes or writes. Preserve element values through CSS variables and report located build errors for inexact values in build-only styling APIs, including the originating binding and hazard; retain exact reads from proven read-only uses and objects frozen before escape.
  • hasDevupUI takes the import aliases and is true for a file extraction changes: one importing a redirected package (@emotion/styled, ...), naming @emotion/react in a @jsxImportSource pragma, or in a project whose tsconfig jsxImportSource is @emotion/react, so the Bun plugin no longer skips files whose only Devup UI is Emotion's css prop or an aliased import. Aliases of Devup UI now compile like the original: export const B = Box, const c = css; export { c as cc }, export const D = Devup and export const C = Devup.css in a barrel (the barrel module exports them as re-exports of the package, and what imports them follows them), export { Box } after an import, export default Box, const D = Devup namespace aliases, and const inner = css declared inside a function. A css() or keyframes() const that a function reads before its declaration compiles. New build error: a css()/keyframes() const read before its declaration runs (outside a function) is located and says to move the declaration above its first read
  • Preserve JavaScript semantics for exact imported enum and Math values including negative zero, lexical constants, binding-aware CommonJS require, React createElement calls, type-only imports, and source-ordered props evaluation with native spread snapshots and CSS-variable fallbacks without a styling runtime. Migrate UI-kit style defaults by pure reordering and test reset CSS through compiled output. Report located build errors for runtime styleOrder values, unknowable whole-object style overrides, opaque selector literals, genuinely unmovable lazy logical suspension, Devup UI namespaces passed whole to runtime code, and immediate style reads in the temporal dead zone of lexical bindings; deferred initialized reads keep folding and pre-assignment var reads remain dynamic.
  • Report extraction, module-resolution and stylesheet execution failures at their original source locations with the cause and repair. Reject recoverable syntax errors, nondeterministic build-time reads, synthetic descriptor/function-source and legacy accessor reflection, and unsafe stylesheet execution fallbacks instead of silently changing CSS. Preserve module resolver and serialization exceptions, evaluate transitive helper side effects, and prevent placeholder-name collisions from losing styles. Match import package names only at exact or slash-delimited boundaries so sibling data packages remain external. Retain helper CSS loads in evaluation order with deduplicated portable relative specifiers and query suffixes, without CSS content dependencies. Report missing CSS or incompatible path roots as located errors, and reject host-recorded unknown CSS export observations even when caught; unused bindings, object passing and typeof follow default TypeScript/JavaScript import semantics.
  • Resolve compiled styling APIs and components by their lexical binding so shadowed local names, including minified library identifiers, remain ordinary JavaScript and JSX. No new build errors; existing diagnostics now apply only to the compiled binding they describe.
  • Styled components the build generates are wrapped in React's forwardRef, so a ref passed to them reaches the element they render on React 18 as well as React 19; the file imports forwardRef from react when it defines one
  • Styled components no longer pass every prop to the tag they render: $ props, theme and the props their style functions or attrs read are kept away from a tag unless it takes them as attributes, and shouldForwardProp (Emotion options or styled-components withConfig) is evaluated at build time. A shouldForwardProp the build cannot evaluate is a build error naming the file, line and code, with the forms it accepts. An element using a styled component the file defines drops props the component neither reads nor passes on; spread props are passed as written
  • Styled components render what their as prop names, defaulting to the tag or component they were defined with, and pass forwardedAs on as as, as styled-components and Emotion do; as used to reach the rendered tag as an attribute. Component.withComponent(target) on a styled component the file binds to a const builds a component rendering the same styles and attrs as target (a tag name or a component JSX can name), where it used to call a method the generated function does not have and throw

@devup-ui/bun-plugin@1.0.22 → 1.0.23 - packages/bun-plugin/package.json

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source
  • hasDevupUI takes the import aliases and is true for a file extraction changes: one importing a redirected package (@emotion/styled, ...), naming @emotion/react in a @jsxImportSource pragma, or in a project whose tsconfig jsxImportSource is @emotion/react, so the Bun plugin no longer skips files whose only Devup UI is Emotion's css prop or an aliased import. Aliases of Devup UI now compile like the original: export const B = Box, const c = css; export { c as cc }, export const D = Devup and export const C = Devup.css in a barrel (the barrel module exports them as re-exports of the package, and what imports them follows them), export { Box } after an import, export default Box, const D = Devup namespace aliases, and const inner = css declared inside a function. A css() or keyframes() const that a function reads before its declaration compiles. New build error: a css()/keyframes() const read before its declaration runs (outside a function) is located and says to move the declaration above its first read

@devup-ui/components@0.1.60 → 0.1.61 - packages/components/package.json

Patch

  • Preserve JavaScript semantics for exact imported enum and Math values including negative zero, lexical constants, binding-aware CommonJS require, React createElement calls, type-only imports, and source-ordered props evaluation with native spread snapshots and CSS-variable fallbacks without a styling runtime. Migrate UI-kit style defaults by pure reordering and test reset CSS through compiled output. Report located build errors for runtime styleOrder values, unknowable whole-object style overrides, opaque selector literals, genuinely unmovable lazy logical suspension, Devup UI namespaces passed whole to runtime code, and immediate style reads in the temporal dead zone of lexical bindings; deferred initialized reads keep folding and pre-assignment var reads remain dynamic.

@devup-ui/next-plugin@1.0.90 → 1.0.91 - packages/next-plugin/package.json

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

@devup-ui/plugin-utils@1.0.17 → 1.0.18 - packages/plugin-utils/package.json

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

@devup-ui/react@1.0.44 → 1.0.45 - packages/react/package.json

Patch

  • Emotion's now compiles at build time with no runtime: the element becomes what its child function ({ css, cx, theme }) => ... renders, each css and cx call becomes the classes it composes (later styles replace earlier ones; css reads strings as CSS text and its tagged templates split around mixins; cx keeps unknown classes, reads { name: condition } objects as conditional classes and composes nested css and cx calls), and theme.a.b in their values becomes var(--a-b). Numbers in css rules are px lengths, as Emotion reads them, and top-level constants are inlined. New build errors, each at file:line:col: a without exactly one child function taking { css, cx, theme } that gives what it renders at once (attributes, other children, rest or default parameters, async or generator functions, several statements); reading the theme other than as theme.a.b in a css value; using css or cx other than by calling them; a cx object with a spread, getter or method; parts css and cx cannot compose (runtime calls, spreads, a condition choosing between styles and classes). @devup-ui/react/compat exports ClassNames with the ClassNamesContent and ClassNamesArg types, and the @emotion/react declarations include them
  • Emotion's css prop compiles at build time while @emotion/react is aliased: on tags and Devup UI components always, and on every element once the file imports @emotion/react or @emotion/styled or names @emotion/react in a @jsxImportSource pragma; jsx, jsxs and jsxDEV from @emotion/react/jsx-runtime (or jsx-dev-runtime) and jsx from @emotion/react compile it too, so libraries built with Emotion's JSX runtime do as well. The prop becomes the element's className, with CSS variables in its style for values only the runtime gives: arrays and conditions compose with a later part replacing what an earlier one sets, css() classes the file knows compose by their styles, strings and templates are CSS text, css`` mixins split the text around them, a function of the theme reads theme.a.b as var(--a-b), unitless numbers are px as in Emotion (constants included), and a className holding known css() classes overrides the prop as Emotion's registered classes do. A styled component the file defines renders its tag in the element's place when the prop overrides its styles and it renders a tag with no attrs or props read and the element has no spread, as or forwardedAs. Emotion's JSX runtime imports become react/jsx-runtime, the pragma names react, and jsx comes from @devup-ui/react/compat (React's createElement); @devup-ui/react/compat/css-prop types the prop on React.Attributes. New build errors, each with file:line:column and the code: a css prop part the build cannot read (a call, an element), a style object declared inside a function or with let, a binding only running the module gives or code changes, a theme function that does more than return rules or reads the theme other than as theme.a.b in a value, an interpolation CSS text cannot place or a mixin inside a nested rule, and a css prop overriding a styled component's styles where its tag cannot be rendered in place. Composing css() with a part that reads a known binding (such as a keyframes name) now reads its value
  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

@devup-ui/reset-css@1.0.31 → 1.0.32 - packages/reset-css/package.json

Patch

  • Preserve JavaScript semantics for exact imported enum and Math values including negative zero, lexical constants, binding-aware CommonJS require, React createElement calls, type-only imports, and source-ordered props evaluation with native spread snapshots and CSS-variable fallbacks without a styling runtime. Migrate UI-kit style defaults by pure reordering and test reset CSS through compiled output. Report located build errors for runtime styleOrder values, unknowable whole-object style overrides, opaque selector literals, genuinely unmovable lazy logical suspension, Devup UI namespaces passed whole to runtime code, and immediate style reads in the temporal dead zone of lexical bindings; deferred initialized reads keep folding and pre-assignment var reads remain dynamic.

@devup-ui/rsbuild-plugin@1.0.67 → 1.0.68 - packages/rsbuild-plugin/package.json

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

@devup-ui/vite-plugin@1.0.73 → 1.0.74 - packages/vite-plugin/package.json

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

@devup-ui/webpack-plugin@1.0.71 → 1.0.72 - packages/webpack-plugin/package.json

Patch

  • A project whose tsconfig.json (or jsconfig.json) builds JSX with Emotion (compilerOptions.jsxImportSource of @emotion/react, through extends and project references too) now compiles the css prop on every element of every file, and its .tsx and .jsx files are built with React's JSX runtime through a /** @jsxImportSource react */ pragma, which a file's own JSX pragma overrides, so the bundler no longer imports Emotion's runtime. The plugins read the setting into a new @emotion/react/jsx-runtime alias (importAliases can turn it off with false, and it is left out when @emotion/react is not aliased); @devup-ui/react/compat/emotion-jsx-runtime declares Emotion's JSX runtimes as React's so the project type-checks without Emotion installed. plugin-utils exports readJsxImportSource, and mergeImportAliases takes the JSX import source

@codecov

codecov Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

Files with missing lines Coverage Δ
bindings/devup-ui-wasm/src/lib.rs 100.00% <ø> (ø)
bindings/devup-ui-wasm/src/resolver_state.rs 100.00% <100.00%> (ø)
libs/css/src/lib.rs 100.00% <100.00%> (ø)
libs/css/src/theme_tokens.rs 100.00% <ø> (ø)
libs/extractor/src/barrel.rs 100.00% <100.00%> (ø)
libs/extractor/src/barrel/aliases.rs 100.00% <100.00%> (ø)
libs/extractor/src/barrel/gate.rs 100.00% <100.00%> (ø)
libs/extractor/src/barrel/namespace_aliases.rs 100.00% <100.00%> (ø)
libs/extractor/src/build_time_values.rs 100.00% <100.00%> (ø)
libs/extractor/src/build_time_values/exact_math.rs 100.00% <100.00%> (ø)
... and 64 more

... and 43 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

owjs3901 and others added 7 commits October 6, 2026 08:22
Keep module-local object identity hazards independent of constant evaluation; preserve element CSS variables and attach originating hazard diagnostics to build-only style reads. Add explicit plain-data builtin policies, shallow-freeze proofs, scalar snapshot handling and regression coverage.

Refs #694, #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Project only proven scalar values at eager style sites without restoring escaped aggregates or unsafe closures. Preserve independent child slots, primitive shallow copies and frozen own properties, and reject reassigned factory bindings in both static evaluation paths.

Refs #694, #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Limit exemptions to compiled lexical APIs and proven scalar-read helpers, track shallow freeze return identity, and gate exact values behind direct and indirect eval barriers. Preserve immutable compiled aliases and add source-backed hazard, ordering and literal-proof coverage witnesses.

Refs #694, #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Exercise semantic compiled, readonly, eval-cycle and freeze-return policies; narrow shallow-freeze ownership and pass typed call sites to remove impossible states without coverage exclusions. Initialize proof outputs together and preserve namespace uncertainty.

Refs #694, #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Verify identity termination on a real function declaration and preserve frozen own scalars when an escaped reader captures the object.

Refs #694, #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Keep snapshot safety independent of earliest diagnostic selection, enforce eval barriers throughout Boa dependency closures, and retain structured semantic consumer and factory-write origins.

Refs #694, #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Refs #694, #695

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@owjs3901
owjs3901 marked this pull request as ready for review October 6, 2026 08:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant